package educrypt.gui.ctr;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFileChooser;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import educrypt.analysis.Frequencies;
import educrypt.analysis.FrequencyAnalysis;
import educrypt.analysis.FrequencyPair;
import educrypt.commons.Text;
import educrypt.database.EduCryptDatabase;
import educrypt.database.dao.AlphabetDAO;
import educrypt.database.dao.FrequencyAnalysisDAO;
import educrypt.database.dao.TextDAO;
import educrypt.exceptions.EduCryptException;
import educrypt.gui.view.AnalysisResultView;
import educrypt.gui.view.DatabaseView;
import educrypt.gui.view.EditorAlphabetView;
import educrypt.gui.view.EditorKeywordView;
import educrypt.gui.view.EditorTextOptionsView;
import educrypt.gui.view.MainView;
import educrypt.i18n.Messages;
import educrypt.io.CSVFile;
import educrypt.io.Output;

public class DatabaseCtr implements ActionListener, ListSelectionListener,
		Observer {

	// View
	private MainView view;
	private DatabaseView databaseView;

	// Model
	private List<Text> texts;
	private List<FrequencyAnalysis> analysis;

	private EduCryptDatabase eduCryptDatabase;
	private TextDAO textDAO;
	private FrequencyAnalysisDAO frequencyAnalysisDAO;

	private CSVFile analysisCsvResults;

	public DatabaseCtr(MainView view) {
		this.view = view;
		this.databaseView = view.getDatabasePanel();

		this.eduCryptDatabase = EduCryptDatabase.getInstance();
		this.textDAO = TextDAO.getInstance();
		this.frequencyAnalysisDAO = FrequencyAnalysisDAO.getInstance();

		this.showTexts();
	}

	private void showTexts() {
		// Model
		texts = textDAO.findAll();
		databaseView.showTextTableValues(textListToMatrixList(texts));

		analysisCsvResults = new CSVFile();
	}

	private List<List<String>> textListToMatrixList(List<Text> texts) {
		List<List<String>> matrix = new ArrayList<List<String>>();
		for (Text t : texts) {
			List<String> lText = new ArrayList<String>();
			lText.add(t.getName());
			lText.add(t.getType());
			lText.add(t.getLanguage());
			matrix.add(lText);
		}
		return matrix;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		try {
			String command = e.getActionCommand();
			if (command.equals(DatabaseView.REMOVE_TEXT)) {
				removeText();
			}
			if (command.equals(DatabaseView.REMOVE_ANALYSIS)) {
				removeAnalysis();
			}
			if (command.equals(DatabaseView.DETAIL_ANALYSIS)) {
				showAnalysisDetail();
			}
			if (command.equals(DatabaseView.EDITOR_TEXT_TYPES)) {
				EditorTextOptionsView editorTextTypeView = view
						.getEditorTextTypeDialog();
				// Open editor
				editorTextTypeView.open((Component) databaseView);

			}
			if (command.equals(DatabaseView.EDITOR_TEXT_LANGUAGES)) {
				EditorTextOptionsView editorTextLanguageView = view
						.getEditorTextLanguageDialog();
				// Open editor
				editorTextLanguageView.open((Component) databaseView);

			}
			if (command.equals(DatabaseView.EDITOR_ALPHABETS)) {
				EditorAlphabetView editorAlphabetView = view
						.getEditorAlphabetDialog();
				// Open editor
				editorAlphabetView.open((Component) databaseView);

			}
			if (command.equals(DatabaseView.EDITOR_KEYWORDS)) {
				EditorKeywordView editorKeywordView = view
						.getEditorKeywordDialog();
				// Set the same selected cipher and alphabet
				editorKeywordView.setSelectedCipher(0);
				// Open editor
				editorKeywordView.open((Component) databaseView);
			}
			if (command.equals(DatabaseView.EXPORT_DB)) {
				databaseView.getSaveDialog().showSaveDialog();
			}
			if (command.equals(DatabaseView.IMPORT_DB)) {
				if (databaseView.showImportConfirmation() == 0) {
					databaseView.getLoadDialog().showOpenDialog();
				}
			}

			if (command.equals(AnalysisResultView.SAVE_RESULT)) {
				databaseView.getAnalyisisDetailDialog()
						.getAnalysisResultPanel().getSaveFileDialog()
						.showSaveDialog();
			}

			if (command.equals(JFileChooser.APPROVE_SELECTION)) {
				JFileChooser source = (JFileChooser) e.getSource();

				if (source.getDialogType() == JFileChooser.SAVE_DIALOG) { // Save
																			// Analysis
					if (this.databaseView.getAnalyisisDetailDialog()
							.isVisible()) {
						AnalysisResultView resultView = databaseView
								.getAnalyisisDetailDialog()
								.getAnalysisResultPanel();
						String filePath = resultView.getSaveFileDialog()
								.getSelectedFile().getAbsolutePath();
						// String frequencies = resultView.getFrequencies();
						Output.writePlainText(analysisCsvResults.getCSV(),
								filePath);

					} else { // Export DB
						String exportFile = databaseView.getSaveDialog()
								.getSelectedFile().getAbsolutePath();
						eduCryptDatabase.exportDatabase(exportFile);
					}

				} else if (source.getDialogType() == JFileChooser.OPEN_DIALOG) { // Import
																					// DB
					String importFile = databaseView.getLoadDialog()
							.getSelectedFile().getAbsolutePath();
					eduCryptDatabase.importDatabase(importFile);
				}
			}
		} catch (EduCryptException ex) {
			view.showExceptionDialog(ex.getMessage());
		}
	}

	private void removeText() {
		int selectedTextIndex = databaseView.getSelectedText();
		if (selectedTextIndex != -1) {
			Text textToRemove = this.texts.get(selectedTextIndex);
			textDAO.delete(textToRemove.getContentHash());
			databaseView.removeAnalysisTableValues();
			databaseView.removeSelectedTextValue();
			texts.remove(textToRemove);
		}
	}

	private void removeAnalysis() {
		int selectedAnalysisIndex = databaseView.getSelectedAnalysis();
		if (selectedAnalysisIndex != -1) {
			FrequencyAnalysis analysisToRemove = this.analysis
					.get(selectedAnalysisIndex);
			frequencyAnalysisDAO.delete(analysisToRemove);
			databaseView.removeSelectedAnalysisValue();
			this.analysis.remove(analysisToRemove);
		}
	}

	@Override
	public void update(Observable o, Object arg) {
		if (o instanceof TextDAO) {
			showTexts();
		}
		if (o instanceof FrequencyAnalysisDAO) {
			showAnalysis();
		}
		if (o instanceof AlphabetDAO) {
			showAnalysis();
		}

	}

	private void showAnalysis() {
		int selectedTextIndex = databaseView.getSelectedText();
		if (selectedTextIndex != -1) {
			Text selectedText = texts.get(selectedTextIndex);

			analysis = FrequencyAnalysisDAO.getInstance().findByTextId(
					selectedText);
			databaseView
					.showAnalysisTableValues(analysisListToMatrixList(analysis));
		}
	}

	private void showAnalysisDetail() {
		AnalysisResultView analysisResultView = databaseView
				.getAnalyisisDetailDialog().getAnalysisResultPanel();

		int selectedTextIndex = databaseView.getSelectedText();
		int selectedAnalysisIndex = databaseView.getSelectedAnalysis();

		if (selectedTextIndex > -1 && selectedAnalysisIndex > -1) {
			Text selectedText = this.texts.get(databaseView.getSelectedText());
			analysisResultView.initializeResult(selectedText.getName());
			FrequencyAnalysis selectedAnalysis = this.analysis.get(databaseView
					.getSelectedAnalysis());
			Frequencies freq = selectedAnalysis.getFrequencies();

			analysisCsvResults = new CSVFile();
			// Initialize the csv "columns"
			analysisCsvResults.addRow(new String[] {
					Messages.getString("guiAnalysisResultSymbol"),
					Messages.getString("guiAnalysisResultFrequency"),
					Messages.getString("guiAnalysisResultPercentage") });

			for (FrequencyPair pair : freq) {
				String symbol = pair.getSymbols();
				int absoluteFrequency = freq.getAbsoluteFrequency(symbol);
				analysisResultView.addResult(pair.getSymbols(),
						pair.getPercentage(), absoluteFrequency);

				// Save in the csv format
				DecimalFormat twoDecimal = new DecimalFormat("#.##");
				DecimalFormat zeroDecimal = new DecimalFormat("#");

				analysisCsvResults.addRow(new String[] { pair.getSymbols(),
						zeroDecimal.format(absoluteFrequency),
						twoDecimal.format(pair.getPercentage()) });
			}
			analysisResultView.setPanelEnabled(true);
			analysisResultView.showResult(true);

			databaseView.showAnalysisDetail();
		}
	}

	@Override
	public void valueChanged(ListSelectionEvent e) {
		if (!e.getValueIsAdjusting()) {
			showAnalysis();
		}
	}

	private List<List<String>> analysisListToMatrixList(
			List<FrequencyAnalysis> analysis) {
		List<List<String>> matrix = new ArrayList<List<String>>();

		for (FrequencyAnalysis fa : analysis) {
			List<String> lAnalysis = new ArrayList<String>();
			lAnalysis.add(fa.getAlphabet().getName());
			lAnalysis.add(Integer.toString(fa.getNgramSize()));
			matrix.add(lAnalysis);
		}
		return matrix;
	}
}
